import static org.junit.Assert.*;
import junit.framework.Assert;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public class VendingMachineTest {

	VendingMachine VendingMachine1, VendingMachine2;
	VendingMachineItem VendingMachineItem1, VendingMachineItem2,VendingMachineItem3;
	
	@Before
	public void setUp() throws Exception {
		VendingMachine1 = new VendingMachine();
		VendingMachine2 = new VendingMachine();
		
		VendingMachineItem1 = new VendingMachineItem("Cookies", 2.5);
		VendingMachineItem2 = new VendingMachineItem("Hershy", 2.65);
		VendingMachineItem3 = new VendingMachineItem("Bounty", 0);

	}

	@After
	public void tearDown() throws Exception {
	}
	
	/********** addItem() - test cases **********\
	
	/**
	 * This method tests adding a new valid item into a vaild slot(A)
	 */
	@Test
	public void testAddItemA(){
		VendingMachine1.addItem(VendingMachineItem1, "A");
		VendingMachine1.addItem(VendingMachineItem1, "B");
		VendingMachine1.addItem(VendingMachineItem1, "C");
		VendingMachine1.addItem(VendingMachineItem1, "D");
		assertEquals(this.VendingMachineItem1, VendingMachine1.getItem("A"));
		assertEquals(this.VendingMachineItem1, VendingMachine1.getItem("B"));
		assertEquals(this.VendingMachineItem1, VendingMachine1.getItem("C"));
		assertEquals(this.VendingMachineItem1, VendingMachine1.getItem("D"));

	}
	
	
	/**
	 * This method tests adding a new valid item into invalid slot.
	 * addItem() must throw an exception
	 */
	@Test (expected = VendingMachineException.class)
	public void testAddItemInvalidSlot() {
		VendingMachine1.addItem(VendingMachineItem1, "E");
	}
	
	/**
	 * This method tests adding a new valid item into occupied slot
	 * addItem() must throw an exception
	 */
	@Test (expected = VendingMachineException.class)
	public void testAddItemOccupiedlot(){
		VendingMachine1.addItem(VendingMachineItem1, "A");
		VendingMachine1.addItem(VendingMachineItem1, "A");
	}
	
	
	/********** removeItem() - test cases **********\
	
	/**
	 * This method test removing an item from vaild slot
	 */
	@Test
	public void testRemoveItemValidSlot(){
		VendingMachine1.addItem(VendingMachineItem1, "A");
		VendingMachine1.removeItem("A");
		assertNull(VendingMachine1.getItem("A"));
	}
	
	/**
	 * This method test removing an item from invalid slot
	 * removeItem() must throw an exception
	 */
	@Test (expected = VendingMachineException.class)
	public void testRemoveItemInvalidSlot(){
		VendingMachine1.addItem(VendingMachineItem1, "A");
		VendingMachine1.removeItem("F");
	}
	
	/**
	 * This method test removing an item from empty slot
	 * removeItem() must throw an exception
	 */
	@Test (expected = VendingMachineException.class)
	public void testRemoveItemEmptySlot(){
		VendingMachine1.addItem(VendingMachineItem1, "A");
		VendingMachine1.removeItem("B");
	}
	
	
	/********** insertMoney() - test cases **********\
	 
	 /**
	  * This methods tests inserting a valid amount into the vending machine
	  */
	@Test
	public void testInsertMoneyValidAmount(){
		VendingMachine1.insertMoney(3.5);
		assertEquals(3.5, VendingMachine1.balance, 0.0001);
	}
	
	/**
	 * This method test inserting invalid amount into the vending machine
	 * insertMoney() must throw an exception
	 */
	@Test (expected = VendingMachineException.class)
	public void testInsertMoneyInvalidAmount() {
		VendingMachine1.insertMoney(-2.5);
	}
	
	
	/********** getBalance() - test cases **********\

	/**
	 * This method test getting the current balance from the vending machine
	 * after single insertion
	 */
	@Test
	public void testGetBalanceSingle(){
		VendingMachine1.insertMoney(5.50);
		assertEquals(VendingMachine1.getBalance(), VendingMachine1.balance, 0.0001);
	}
	
	/**
	 * This method test getting the current balance from the vending machine
	 * after multiple insertions
	 */
	@Test
	public void testGetBalanceMulti(){
		VendingMachine1.insertMoney(5.50);
		VendingMachine1.insertMoney(2);
		VendingMachine1.insertMoney(3.65);
		assertEquals(VendingMachine1.getBalance(), VendingMachine1.balance, 0.0001);
	}
	
	
	/********** getBalance() - test cases **********\

	/**
	 * This method tests purchasing an item from the vending machine
	 * on valid item
	 */
	@Test
	public void testMakePurchase(){
		VendingMachine1.addItem(VendingMachineItem1, "A");
		VendingMachine1.insertMoney(3);
		assertEquals(true, VendingMachine1.makePurchase("A"));
	}

	
	/**
	 * This method tests purchasing an item from the vending machine on empty slot
	 * makePurchase() must throw exception
	 */
	public void testMakePurchaseEmptySlot(){
		VendingMachine1.addItem(VendingMachineItem1, "A");
		VendingMachine1.insertMoney(3);
		assertEquals(false, VendingMachine1.makePurchase("D"));
	}

	/**
	 * This method tests purchasing an item from the vending machine when
	 * balance less than item's price
	 * makePurchase() must throw exception
	 */
	public void testMakePurchaseInvalidAmount(){
		VendingMachine1.addItem(VendingMachineItem1, "A");
		VendingMachine1.insertMoney(1.25);
		assertEquals(false, VendingMachine1.makePurchase("A"));
	}
	
	
	/********** getBalance() - test cases **********\
	 
	 /**
	  * This method test returning the change after making the purchase
	  */
	@Test
	public void testReturnChange(){
		VendingMachine1.addItem(VendingMachineItem1, "A");
		VendingMachine1.insertMoney(4);
		VendingMachine1.makePurchase("A");
		Assert.assertEquals(1.5, VendingMachine1.returnChange(), 0.0001);
	}
	
	/**
	  * This method test returning zero/return nothing, if the inserted amount equal
	  * to the item's price
	  */
	@Test
	public void testReturnChangeZero(){
		VendingMachine1.addItem(VendingMachineItem1, "A");
		VendingMachine1.insertMoney(2.5);
		VendingMachine1.makePurchase("A");
		Assert.assertEquals(0, VendingMachine1.returnChange(), 0.0001);
	}
	
}

